<template>
<<<<<<< HEAD
  <div id="antv">
    <splitpanes class="default-theme" vertical style="height: 600px">
=======
  <div class="header-bar">
    <span class="title-text">虚拟原型产品开发工具</span>
  </div>
  <div style="display: flex; align-items: center; height: 60px; position: relative;">
  <!-- 左侧按钮组（固定宽度） -->
  <div style="display: flex; align-items: center;">
          <el-button @click="openDialog" type="primary" style="width: 110px; margin-right: 20px;">上传文件</el-button>
      <el-input v-model="res" readonly style="width: 500px;margin-right: 20px;" placeholder="请上传ELF文件或者Bin文件"/>
      <el-button @click="start" type="primary" style="width: 110px; margin-right: 20px;">运行</el-button>
       <el-button @click="stopp" type="danger" style="width: 110px; margin-right: 20px;">停止</el-button>
      <el-button @click="toggleTerminal" type="primary" style="width: 110px; margin-right: 20px;">打开终端</el-button>
    <el-dropdown @command="handleSaveCommand" trigger="click">
        <el-button type="primary" style="width: 110px;margin-right: 20px;">
          保存<el-icon class="el-icon--right"><arrow-down /></el-icon>
        </el-button>
        <template #dropdown>
          <el-dropdown-menu>
            <el-dropdown-item v-if="currentGraphName" command="save_current">
              Save to {{ currentGraphName }}
            </el-dropdown-item>
            <el-dropdown-item command="save_new">保存到一个新的项目</el-dropdown-item>
          </el-dropdown-menu>
        </template>
      </el-dropdown>
      
      <el-dialog v-model="showSaveDialog" title="Save new project" width="30%">
        <el-input v-model="newGraphName" placeholder="Please input the name of new project" />
        <template #footer>
          <el-button @click="showSaveDialog = false">Cancel</el-button>
          <el-button type="primary" @click="saveNewCanvas">Save</el-button>
        </template>
      </el-dialog>
    <el-button type="primary"  style="width: 110px" @click="navigateToToolsPage">查看开发工具</el-button>
  </div>

  <!-- 绝对居中的标题 -->
  <!-- <span style="
    position:absolute;
    left: 50%;
    transform: translateX(-50%);
    white-space: nowrap;
    line-height: 1.5; /* 保持与按钮同高 */
    font-size: 25px;
  ">
    virtual HW product protyping tool 虚拟原型产品开发工具
  </span> -->

  <!-- 右侧占位块（保持对称） -->
  <div style="width: 230px; visibility: hidden;">占位</div>
</div>
  <div id="antv">
    <splitpanes class="default-theme" vertical style="height: 1000px">
>>>>>>> v3.0
      <!-- <pane size="" ><div id="stencil"></div></pane> -->
      <pane size="" id="stencil"></pane>
      <pane>
        <Splitpanes horizontal>
          <pane><div id="graph-container"></div></pane>
          <pane v-if="showTerminal">
<<<<<<< HEAD
            <Term />
          </pane>
        </Splitpanes>
      </pane>

=======
            <Term style="width: 100%;"/>
          </pane>
        </Splitpanes>
      </pane>
>>>>>>> v3.0
    </splitpanes>
  </div>
</template>

<script setup lang="ts">
<<<<<<< HEAD
import { Graph, Shape } from '@antv/x6'
import { Stencil } from '@antv/x6-plugin-stencil'
import { Transform } from '@antv/x6-plugin-transform'
import { Selection } from '@antv/x6-plugin-selection'
import { Snapline } from '@antv/x6-plugin-snapline'
import { Keyboard } from '@antv/x6-plugin-keyboard'
import { Clipboard } from '@antv/x6-plugin-clipboard'
import { History } from '@antv/x6-plugin-history'
import { invoke } from '@tauri-apps/api';
import { open, save } from '@tauri-apps/api/dialog';
import { writeTextFile, readTextFile } from '@tauri-apps/api/fs';
import { onMounted,onBeforeMount } from 'vue'
import { Splitpanes, Pane } from 'splitpanes';
import 'splitpanes/dist/splitpanes.css';
import Term from './Term.vue';

// import insertCss from 'insert-css'

// 为了协助代码演示
onMounted(() => {
// #region 初始化画布
const graph = new Graph({
  container: document.getElementById('graph-container')!,
  grid: true,
  mousewheel: {
    enabled: true,
    zoomAtMousePosition: true,
    modifiers: 'ctrl',
    minScale: 0.5,
    maxScale: 3,
  },
  connecting: {
    router: 'manhattan',
    connector: {
      name: 'rounded',
      args: {
        radius: 8,
      },
    },
    anchor: 'center',
    connectionPoint: 'anchor',
    allowBlank: false,
    snap: {
      radius: 20,
    },
    createEdge() {
      return new Shape.Edge({
        attrs: {
          line: {
            stroke: '#A2B1C3',
            strokeWidth: 2,
            targetMarker: {
              name: 'block',
              width: 12,
              height: 8,
            },
          },
        },
        zIndex: 0,
      })
    },
    validateConnection({ targetMagnet }) {
      return !!targetMagnet
    },
  },
  highlighting: {
    magnetAdsorbed: {
      name: 'stroke',
      args: {
        attrs: {
          fill: '#5F95FF',
          stroke: '#5F95FF',
        },
      },
    },
  },
})
// #endregion
// #region 使用插件
graph
  .use(
    new Transform({
      resizing: true,
      rotating: true,
    }),
  )
  .use(
    new Selection({
      rubberband: true,
      showNodeSelectionBox: true,
    }),
  )
  .use(new Snapline())
  .use(new Keyboard())
  .use(new Clipboard())
  .use(new History())
// #endregion

// #region 初始化 stencil
const stencil = new Stencil({
  title: 'examples',
  target: graph,
  stencilGraphWidth: 500,
  stencilGraphHeight: 180,
  collapsable: true,
  groups: [
    {
      title: 'peripherals',
      name: 'group1',
    },
    {
      title: 'boards',
      name: 'group2',
      graphHeight: 250,
      layoutOptions: {
        rowHeight: 70,
      },
    },
  ],
  layoutOptions: {
    columns: 2,
    columnWidth: 80,
    rowHeight: 55,
  },
})
document.getElementById('stencil')!.appendChild(stencil.container)
// #endregion

// #region 快捷键与事件
graph.bindKey(['meta+c', 'ctrl+c'], () => {
  const cells = graph.getSelectedCells()
  if (cells.length) {
    graph.copy(cells)
  }
  return false
})
graph.bindKey(['meta+x', 'ctrl+x'], () => {
  const cells = graph.getSelectedCells()
  if (cells.length) {
    graph.cut(cells)
  }
  return false
})
graph.bindKey(['meta+v', 'ctrl+v'], () => {
  if (!graph.isClipboardEmpty()) {
    const cells = graph.paste({ offset: 32 })
    graph.cleanSelection()
    graph.select(cells)
  }
  return false
})

// undo redo
graph.bindKey(['meta+z', 'ctrl+z'], () => {
  if (graph.canUndo()) {
    graph.undo()
  }
  return false
})
graph.bindKey(['meta+shift+z', 'ctrl+shift+z'], () => {
  if (graph.canRedo()) {
    graph.redo()
  }
  return false
})

// select all
graph.bindKey(['meta+a', 'ctrl+a'], () => {
  const nodes = graph.getNodes()
  if (nodes) {
    graph.select(nodes)
  }
})

// delete
graph.bindKey('backspace', () => {
  const cells = graph.getSelectedCells()
  if (cells.length) {
    graph.removeCells(cells)
  }
})

// zoom
graph.bindKey(['ctrl+1', 'meta+1'], () => {
  const zoom = graph.zoom()
  if (zoom < 1.5) {
    graph.zoom(0.1)
  }
})
graph.bindKey(['ctrl+2', 'meta+2'], () => {
  const zoom = graph.zoom()
  if (zoom > 0.5) {
    graph.zoom(-0.1)
  }
})

// 控制连接桩显示/隐藏
const showPorts = (ports: NodeListOf<SVGElement>, show: boolean) => {
  for (let i = 0, len = ports.length; i < len; i += 1) {
    ports[i].style.visibility = show ? 'visible' : 'hidden'
  }
}
graph.on('node:mouseenter', () => {
  const container = document.getElementById('graph-container')!
  const ports = container.querySelectorAll(
    '.x6-port-body',
  ) as NodeListOf<SVGElement>
  showPorts(ports, true)
})
graph.on('node:mouseleave', () => {
  const container = document.getElementById('graph-container')!
  const ports = container.querySelectorAll(
    '.x6-port-body',
  ) as NodeListOf<SVGElement>
  showPorts(ports, false)
})

graph.on('node:contextmenu', ({ node }) => {
  // 获取节点的 label 值
  const sourceLabel = node?.label;
  // console.log('Source Node Labelhhhhhhhhhha:', sourceLabel);
  // e.preventDefault(); // 阻止默认右键菜单
  showContextMenu(sourceLabel);
});

graph.on('edge:connected', ({ edge }) => {
  // 获取连接线的源节点和目标节点
  const sourceNode = edge.getSourceNode();
  const targetNode = edge.getTargetNode();

  // 获取节点的 label 值
  const sourceLabel = sourceNode?.label;
  const targetLabel = targetNode?.label;

  // invoke('user_repl', {source:sourceLabel, target:targetLabel});

  console.log('Source Node Label:', sourceLabel);
  console.log('Source Node Label:', typeof (sourceLabel));
  console.log('Target Node Label:', targetLabel);
});
async function onclick(sourceLabel, select1Value, input1, select2Value, input2) {
  console.log('sourceLabel:', sourceLabel);
  console.log('sourceLabeltype:', typeof (sourceLabel));
  console.log('select1Value:', select1Value);
  console.log('select1Valuetype:', typeof (select1Value));
  console.log('input1:', input1);
  console.log('input1type:', typeof (input1));
  console.log('select2Value:', select2Value);
  console.log('input2:', input2);
  // 在用invoke向tauri传递参数的时候要注意vue这边的参数名称可能与tauri那边不一致。
  invoke('add_repl', { source: sourceLabel, target: select1Value, targetValue: input1, interruptTarget: select2Value, interruptIndex: input2 });
}

async function showContextMenu(sourceLabel) {
  const contextMenu = document.createElement('div');
  contextMenu.style.position = 'absolute';
  contextMenu.style.left = `${event.clientX}px`;
  contextMenu.style.top = `${event.clientY}px`;
  contextMenu.style.backgroundColor = '#fff';
  contextMenu.style.border = '1px solid #ddd';
  contextMenu.style.padding = '10px';

  // 创建下拉选择框
  const select1 = document.createElement('select');
  // 添加选项
  const option11 = document.createElement('option');
  option11.value = 'gpioPortA';
  option11.text = 'gpioPortA';
  select1.add(option11);

  const option12 = document.createElement('option');
  option12.value = 'gpioPortB';
  option12.text = 'gpioPortB';
  select1.add(option12);

  const option13 = document.createElement('option');
  option13.value = 'gpioPortC';
  option13.text = 'gpioPortC';
  select1.add(option13);

  const option14 = document.createElement('option');
  option14.value = 'gpioPortD';
  option14.text = 'gpioPortD';
  select1.add(option14);

  contextMenu.appendChild(select1);

  // 创建文本框
  const input1 = document.createElement('input');
  input1.type = 'text';
  input1.placeholder = 'Enter text...';
  contextMenu.appendChild(input1);

  // 创建下拉选择框
  const select2 = document.createElement('select');
  // 添加选项
  const option21 = document.createElement('option');
  option21.value = 'gpioPortA';
  option21.text = 'gpioPortA';
  select2.add(option21);

  const option22 = document.createElement('option');
  option22.value = 'gpioPortB';
  option22.text = 'gpioPortB';
  select2.add(option22);

  const option23 = document.createElement('option');
  option23.value = 'gpioPortC';
  option23.text = 'gpioPortC';
  select2.add(option23);

  const option24 = document.createElement('option');
  option24.value = 'gpioPortD';
  option24.text = 'gpioPortD';
  select2.add(option24);

  contextMenu.appendChild(select2);

  // 创建文本框
  const input2 = document.createElement('input');
  input2.type = 'text';
  input2.placeholder = 'Enter text...';
  contextMenu.appendChild(input2);

  // 创建按钮
  const button = document.createElement('button');
  button.textContent = 'Enter';
  button.onclick = () => {
    // 在按钮点击时执行onclick函数
    onclick(sourceLabel, select1.value, input1.value, select2.value, input2.value);
    document.body.removeChild(contextMenu); // 移除菜单
  };
  contextMenu.appendChild(button);

  // 将菜单添加到页面
  document.body.appendChild(contextMenu);
}


// #endregion

// #region 初始化图形
const ports = {
  groups: {
    top: {
      position: 'top',
      attrs: {
        circle: {
          r: 4,
          magnet: true,
          stroke: '#5F95FF',
          strokeWidth: 1,
          fill: '#fff',
          style: {
            visibility: 'hidden',
          },
        },
      },
    },
    right: {
      position: 'right',
      attrs: {
        circle: {
          r: 4,
          magnet: true,
          stroke: '#5F95FF',
          strokeWidth: 1,
          fill: '#fff',
          style: {
            visibility: 'hidden',
          },
        },
      },
    },
    bottom: {
      position: 'bottom',
      attrs: {
        circle: {
          r: 4,
          magnet: true,
          stroke: '#5F95FF',
          strokeWidth: 1,
          fill: '#fff',
          style: {
            visibility: 'hidden',
          },
        },
      },
    },
    left: {
      position: 'left',
      attrs: {
        circle: {
          r: 4,
          magnet: true,
          stroke: '#5F95FF',
          strokeWidth: 1,
          fill: '#fff',
          style: {
            visibility: 'hidden',
          },
        },
      },
    },
  },
  items: [
    {
      group: 'top',
    },
    {
      group: 'right',
    },
    {
      group: 'bottom',
    },
    {
      group: 'left',
    },
  ],
}

Graph.registerNode(
  'custom-rect',
  {
    inherit: 'rect',
    width: 66,
    height: 36,
    attrs: {
      body: {
        strokeWidth: 1,
        stroke: '#5F95FF',
        fill: '#EFF4FF',
      },
      text: {
        fontSize: 12,
        fill: '#262626',
      },
    },
    ports: { ...ports },
  },
  true,
)

Graph.registerNode(
  'custom-polygon',
  {
    inherit: 'polygon',
    width: 66,
    height: 36,
    attrs: {
      body: {
        strokeWidth: 1,
        stroke: '#5F95FF',
        fill: '#EFF4FF',
      },
      text: {
        fontSize: 12,
        fill: '#262626',
      },
    },
    ports: {
      ...ports,
      items: [
        {
          group: 'top',
        },
        {
          group: 'bottom',
        },
      ],
    },
  },
  true,
)

Graph.registerNode(
  'custom-circle',
  {
    inherit: 'circle',
    width: 45,
    height: 45,
    attrs: {
      body: {
        strokeWidth: 1,
        stroke: '#5F95FF',
        fill: '#EFF4FF',
      },
      text: {
        fontSize: 12,
        fill: '#262626',
      },
    },
    ports: { ...ports },
  },
  true,
)

Graph.registerNode(
  'custom-image',
  {
    inherit: 'rect',
    width: 52,
    height: 52,
    markup: [
      {
        tagName: 'rect',
        selector: 'body',
      },
      {
        tagName: 'image',
      },
      {
        tagName: 'text',
        selector: 'label',
      },
    ],
    attrs: {
      body: {
        stroke: '#5F95FF',
        fill: '#5F95FF',
      },
      image: {
        width: 26,
        height: 26,
        refX: 13,
        refY: 16,
      },
      label: {
        refX: 3,
        refY: 2,
        textAnchor: 'left',
        textVerticalAnchor: 'top',
        fontSize: 12,
        fill: '#fff',
      },
    },
    ports: { ...ports },
  },
  true,
)

const r1 = graph.createNode({
  shape: 'custom-rect',
  label: 'LED',
})
const r2 = graph.createNode({
  shape: 'custom-rect',
  label: 'Button',
})
const r3 = graph.createNode({
  shape: 'custom-rect',
  label: 'Sensor',
})
const r4 = graph.createNode({
  shape: 'custom-rect',
  label: 'Screen',
})
const r5 = graph.createNode({
  shape: 'custom-rect',
  label: 'ADC',
})
const r6 = graph.createNode({
  shape: 'custom-rect',
  label: 'Uart',
})
const r7 = graph.createNode({
  shape: 'custom-rect',
  label: 'Uart',
})
stencil.load([r1, r2, r3, r4, r5, r6], 'group1')

const imageShapes = [
  {
    label: 'STM32F4Discovery',
    image: 
    '../../public/Arduino_DUE_V02b_breadboard.svg',
    //'https://gw.alipayobjects.com/zos/bmw-prod/687b6cb9-4b97-42a6-96d0-34b3099133ac.svg',
  },
  {
    label: 'STM32F7Discovery',
    image:
      'https://gw.alipayobjects.com/zos/bmw-prod/dc1ced06-417d-466f-927b-b4a4d3265791.svg',
  },
  {
    label: 'Arudino',
    image:
      'https://gw.alipayobjects.com/zos/bmw-prod/c55d7ae1-8d20-4585-bd8f-ca23653a4489.svg',
  },
  {
    label: 'K210',
    image:
      'https://gw.alipayobjects.com/zos/bmw-prod/6eb71764-18ed-4149-b868-53ad1542c405.svg',
  },
  {
    label: 'NXP',
    image:
      'https://gw.alipayobjects.com/zos/bmw-prod/c36fe7cb-dc24-4854-aeb5-88d8dc36d52e.svg',
  },
  {
    label: 'Xtensa',
    image:
      'https://gw.alipayobjects.com/zos/bmw-prod/2010ac9f-40e7-49d4-8c4a-4fcf2f83033b.svg',
  },
]

graph.on('node:resizing', ({node}) => {
    const size = node.size();
    node.attr('image/width', size.width);
    node.attr('image/height', size.height);
});


const imageNodes = imageShapes.map((item) =>
  graph.createNode({
    shape: 'custom-image',
    label: item.label,
    attrs: {
      image: {
        'xlink:href': item.image,
        // width: 20, // 设置图像初始宽度
        // height: 40, // 设置图像初始高度
      },
    },

    // ports: {
    //   groups: {
    //     group1: {
    //       attrs: {
    //         circle: {
    //           r: 6,
    //           magnet: true,
    //           stroke: '#31d0c6',
    //           fill: '#fff',
    //           strokeWidth: 2,
    //         },
    //       },
    //       position: {
    //         name: 'left',
    //       },
    //     },
    //     group2: {
    //       attrs: {
    //         circle: {
    //           r: 6,
    //           magnet: true,
    //           stroke: '#31d0c6',
    //           fill: '#fff',
    //           strokeWidth: 2,
    //         },
    //       },
    //       position: {
    //         name: 'right',
    //       },
    //     },
    //     group3: {
    //       attrs: {
    //         circle: {
    //           r: 6,
    //           magnet: true,
    //           stroke: '#31d0c6',
    //           fill: '#fff',
    //           strokeWidth: 2,
    //         },
    //       },
    //       position: {
    //         name: 'top',
    //       },
    //     },
    //     group4: {
    //       attrs: {
    //         circle: {
    //           r: 6,
    //           magnet: true,
    //           stroke: '#31d0c6',
    //           fill: '#fff',
    //           strokeWidth: 2,
    //         },
    //       },
    //       position: {
    //         name: 'bottom',
    //       },
    //     },

    //   },
    //   items: [
    //     {
    //       id: 'PA0',
    //       group: 'group1',
    //       attrs: {
    //         text: {
    //           // 标签选择器
    //           text: 'PA0', // 标签文本
    //         },
    //       },
    //     },
    //     {
    //       id: 'PA1',
    //       group: 'group1',
    //       attrs: {
    //         text: {
    //           // 标签选择器
    //           text: 'PA1', // 标签文本
    //         },
    //       },
    //     },
    //     {
    //       id: 'PA2',
    //       group: 'group1',
    //       attrs: {
    //         text: {
    //           // 标签选择器
    //           text: 'PA2', // 标签文本
    //         },
    //       },
    //     },
    //     {
    //       id: 'PA3',
    //       group: 'group1',
    //       attrs: {
    //         text: {
    //           // 标签选择器
    //           text: 'PA3', // 标签文本
    //         },
    //       },
    //     },

    //     {
    //       id: 'PB0',
    //       group: 'group2',
    //       attrs: {
    //         text: {
    //           // 标签选择器
    //           text: 'PB0', // 标签文本
    //         },
    //       },
    //     },
    //     {
    //       id: 'PB1',
    //       group: 'group2',
    //       attrs: {
    //         text: {
    //           // 标签选择器
    //           text: 'PB1', // 标签文本
    //         },
    //       },
    //     },
    //     {
    //       id: 'PB2',
    //       group: 'group2',
    //       attrs: {
    //         text: {
    //           // 标签选择器
    //           text: 'PB2', // 标签文本
    //         },
    //       },
    //     },
    //     {
    //       id: 'PB3',
    //       group: 'group2',
    //       attrs: {
    //         text: {
    //           // 标签选择器
    //           text: 'PB3', // 标签文本
    //         },
    //       },
    //     },
    //   ],
    // },

  }),
)
stencil.load(imageNodes, 'group2')
// #endregion
=======
import { Graph, Shape } from "@antv/x6";
import { Stencil } from "@antv/x6-plugin-stencil";
import { Transform } from "@antv/x6-plugin-transform";
import { Selection } from "@antv/x6-plugin-selection";
import { Snapline } from "@antv/x6-plugin-snapline";
import { Keyboard } from "@antv/x6-plugin-keyboard";
import { Clipboard } from "@antv/x6-plugin-clipboard";
import { History } from "@antv/x6-plugin-history";
import { invoke } from "@tauri-apps/api/core";
import { open, save } from "@tauri-apps/plugin-dialog";
import { writeTextFile, readTextFile } from "@tauri-apps/plugin-fs";
import { onMounted, onBeforeMount } from "vue";
import { Splitpanes, Pane } from "splitpanes";
import "splitpanes/dist/splitpanes.css";
import Term from "./Term.vue";
import { listen } from "@tauri-apps/api/event";
import { er } from "@antv/x6/lib/registry/router/er";
import { useRouter } from 'vue-router'
import { ref } from 'vue';
import { image } from "@tauri-apps/api";
import {Export} from "@antv/x6-plugin-export";
const savedGraphsName = ref<string[]>([]);
const currentGraphName = ref<string>('');
const showSaveDialog = ref(false);
const newGraphName = ref('');
const stencilRef = ref<Stencil | null>(null);

const router = useRouter()
const navigateToToolsPage = () => {
  router.push('/information')  // 或者使用名称 router.push({ name: 'tools' })
}

// import insertCss from 'insert-css'
let graph: Graph | null = null;

let refnode = null;
function stopp(){
  invoke("stop");
  refnode.prop('attrs/image/xlink:href',"../../public/peripherals/f3e38030cc2615977cc05f711b662e79.png"); 
  refnode=null;

}

const selectedFilePath = ref("");
const res = ref("");

async function openDialog(event) {
  event.preventDefault();  // 阻止默认的表单提交行为
  // Open a selection dialog for image files
  const selected = await open({
    multiple: true,
    filters: [{
      name: 'Image',
      extensions: ['*']
    }]
  });
  console.log(selected)
  selectedFilePath.value = selected[0]
  // res.value = selectedFilePath.value
  invoke('add_resc', { name: selectedFilePath.value })
    // `invoke` returns a Promise
    .then((response) => {
      res.value = response
    })
}

const showTerminal=ref(false);
const toggleTerminal=()=>{
    showTerminal.value = !showTerminal.value;
};

async function start(){
  invoke('start', {})
}


// 为了协助代码演示
onMounted(() => {
  // #region 初始化画布
  graph = new Graph({
    container: document.getElementById("graph-container")!,
    width: 1700,
    height: 1000,
    grid: {
      size: 20,
      visible: true,
      type: 'dot',
    },
    interacting: {
      edgeMovable: true,
    },
    background: {
      color: '#DCDCDC',
    },
    mousewheel: {
      enabled: true,
      zoomAtMousePosition: true,
      modifiers: "ctrl",
      minScale: 0.5,
      maxScale: 3,
    },
    connecting: {
      router: "manhattan",
      allowNode: true,
      allowEdge: false,
      connector: {
        name: "rounded",
        args: {
          radius: 8,
        },
      },
      anchor: "center",
      connectionPoint: "anchor",
      allowBlank: false,
      snap: {
        radius: 20,
      },
      createEdge() {
        return new Shape.Edge({
          attrs: {
            line: {
              stroke: "#50B7C1",
              strokeWidth: 2,
              targetMarker: null,
            },
          },
          zIndex: 10,
        });
      },
      validateConnection({ targetMagnet }) {
        return !!targetMagnet;
      },
    },
    highlighting: {
      magnetAdsorbed: {
        name: "stroke",
        args: {
          attrs: {
            fill: "#5F95FF",
            stroke: "#5F95FF",
          },
        },
      },
    },
  });

  // 确保 graph 不为 null
  if (!graph) {
    throw new Error('Failed to initialize graph');
  }

  // #endregion

  // #region 使用插件
  graph
    .use(
      new Transform({
        resizing: true,
        rotating: true,
      })
    )
    .use(
      new Selection({
        rubberband: true,
        showNodeSelectionBox: true,
      })
    )
    .use(new Snapline())
    .use(new Keyboard())
    .use(new Clipboard())
    .use(new History())
    .use(new Export());
  // #endregion

  // #region 初始化 stencil
  const stencil = new Stencil({
    title: "组件库",
    target: graph,
    stencilGraphWidth: 1000,
    stencilGraphHeight: 180,
    collapsable: true,
    stencilGraphOptions: {
    background: {
      color: '#ffffff', // 设置背景颜色
      },
    },
    groups: [
      {
        title: "外设",
        name: "group1",
        graphHeight: 500,
        layoutOptions: {
          rowHeight: 150,
        },
      },
      {
        title: "开发板和控制器",
        name: "group2",
        graphHeight: 500,
        layoutOptions: {
          rowHeight: 150,
        },
      },
      {
        title: "电源",
        name: "group3",
        graphHeight: 330,
        layoutOptions: {
          rowHeight: 150,
        },
      },
      {
        title: "保存",
        name: "group4",
        graphHeight: 500,
        layoutOptions: {
          rowHeight: 150,
        },
      },
    ],
    layoutOptions: {
      columns: 2,
      columnWidth: 120,
      rowHeight: 80,
    },
  });
stencilRef.value = stencil;
const stencilContainer = document.getElementById("stencil")!;
stencilContainer.style.width = "350px"; // 设置侧边栏整体宽度
stencilContainer.appendChild(stencil.container);
  // document.getElementById("stencil")!.appendChild(stencil.container);
  // #endregion

  // #region 快捷键与事件
  graph.bindKey(["meta+c", "ctrl+c"], () => {
    const cells = graph.getSelectedCells();
    if (cells.length) {
      graph.copy(cells);
    }
    return false;
  });
  graph.bindKey(["meta+x", "ctrl+x"], () => {
    const cells = graph.getSelectedCells();
    if (cells.length) {
      graph.cut(cells);
    }
    return false;
  });
  graph.bindKey(["meta+v", "ctrl+v"], () => {
    if (!graph.isClipboardEmpty()) {
      const cells = graph.paste({ offset: 32 });
      graph.cleanSelection();
      graph.select(cells);
    }
    return false;
  });

  // undo redo
  graph.bindKey(["meta+z", "ctrl+z"], () => {
    if (graph.canUndo()) {
      graph.undo();
    }
    return false;
  });
  graph.bindKey(["meta+shift+z", "ctrl+shift+z"], () => {
    if (graph.canRedo()) {
      graph.redo();
    }
    return false;
  });

  // select all
  graph.bindKey(["meta+a", "ctrl+a"], () => {
    const nodes = graph.getNodes();
    if (nodes) {
      graph.select(nodes);
    }
  });

  // delete
  graph.bindKey("backspace", () => {
    const cells = graph.getSelectedCells();
    if (cells.length) {
      graph.removeCells(cells);
    }
  });

  // zoom
  graph.bindKey(["ctrl+1", "meta+1"], () => {
    const zoom = graph.zoom();
    if (zoom < 1.5) {
      graph.zoom(0.1);
    }
  });
  graph.bindKey(["ctrl+2", "meta+2"], () => {
    const zoom = graph.zoom();
    if (zoom > 0.5) {
      graph.zoom(-0.1);
    }
  });

  // 控制连接桩显示/隐藏
  const showPorts = (ports: NodeListOf<SVGElement>, show: boolean) => {
    for (let i = 0, len = ports.length; i < len; i += 1) {
      ports[i].style.visibility = show ? "visible" : "hidden";
    }
  };
  graph.on("node:mouseenter", () => {
    const container = document.getElementById("graph-container")!;
    const ports = container.querySelectorAll(
      ".x6-port-body"
    ) as NodeListOf<SVGElement>;
    showPorts(ports, true);
  });
  graph.on("node:mouseleave", () => {
    const container = document.getElementById("graph-container")!;
    const ports = container.querySelectorAll(
      ".x6-port-body"
    ) as NodeListOf<SVGElement>;
    showPorts(ports, false);
  });

  graph.on("node:contextmenu", ({ node }) => {
    // 获取节点的 label 值
    const sourceLabel = node?.label;
    // console.log('Source Node Labelhhhhhhhhhha:', sourceLabel);
    // e.preventDefault(); // 阻止默认右键菜单
    showContextMenu(sourceLabel);
  });

  graph.on("node:dblclick", ({ node }) => {
    const sourceLabel = node?.label;
    console.log(node.label);

    let d = document.getElementById(sourceLabel);
    console.log(d);

    d && (d.style.display = "none");
  });

  graph.on('node:added', ({ node }) => {
  const data = node.getData(); // 获取节点自定义数据
  if (data?.image && data?.image) {
    node.resize(data.image.width, data.image.height); // 动态调整大小
    node.prop('attrs/image/width', data.image.width); 
    node.prop('attrs/image/height', data.image.height); 
    node.prop('attrs/image/refX', 0); 
    node.prop('attrs/image/refY', 0); 
    node.prop('attrs/label/refX', data.label.refX); 
    node.prop('attrs/label/refY', data.label.refY); 
    node.prop('attrs/label/fontSize', data.label.fontSize); 
  }
  if (node.getData()?.isSavedGraph) {
    const graphName = node.getData().graphName;
    const graphData = JSON.parse(localStorage.getItem(`x6-graph-${graphName}`)!);
    graph.fromJSON(graphData);
    currentGraphName.value = graphName;
    alert(` "${graphName}" 已加载`);
  }
});

  let lednode = null;

  // graph.on("edge:connected", ({ edge }) => {
  //   // 获取连接线的源节点和目标节点
  //   const sourceNode = edge.getSourceNode();
  //   const targetNode = edge.getTargetNode();

  //   // 获取节点的 label 值
  //   const sourceLabel = sourceNode?.label;
  //   const targetLabel = targetNode?.label;

  //   // invoke('user_repl', {source:sourceLabel, target:targetLabel});

  //   console.log("Source Node Label:", sourceLabel);
  //   console.log("Source Node Label:", typeof sourceLabel);
  //   console.log("Target Node Label:", targetLabel);
  //   if (sourceLabel === "LED") {
  //     lednode = sourceNode;
  //     console.warn(`lednode: ${lednode}`);
  //   }
  // });

graph.on('edge:connected', ({ edge }) => {
  // 获取连接信息
  const source = edge.getSource()
  const target = edge.getTarget()
  const sourceNode = edge.getSourceNode()
  const targetNode = edge.getTargetNode()

  console.log('source:', sourceNode.getPort(source.port!).port);

   if(targetNode.label === "LED"){
    lednode = targetNode;
    invoke("add_repl", {
      source: "LED", //小灯LED
      target: "gpioPort"+sourceNode.getPort(source.port!).port.substr(1,1), //gpioPortC
      targetValue: sourceNode.getPort(source.port!).port.substring(2,sourceNode.getPort(source.port!).port.length),  //13
      interruptTarget: "none", //none
      interruptIndex: "1",
    });
  }

    listen("LED_output", (ev: { payload: boolean }) => {
      console.log("11111");
    if (lednode === null) return;
    refnode= lednode;
    if(ev.payload){
      lednode.prop('attrs/image/xlink:href',"../../public/peripherals/5e188a760d2b7b8a02792fcf8ba5b122.png"); 
    }
    else{
      lednode.prop('attrs/image/xlink:href',"../../public/peripherals/f3e38030cc2615977cc05f711b662e79.png"); 
    }
  });
  
  // // 调用 Rust 后端函数
  // invoke("add_repl", {
  //     source: "LED", //小灯LED
  //     target: "gpioPortC", //gpioPortC
  //     targetValue: "15",  //13
  //     interruptTarget: "none", //none
  //     interruptIndex: "1",
  //   });
})


  // 启用边移动（默认已通过edgeMovable启用）
graph.on('edge:mouseenter', ({ edge }) => {
  edge.addTools([         // 悬浮时显示工具
    {
      name: 'vertices',   // 路径点工具
      args: {
        attrs: {
          fill: '#ff8800' // 橙色控制点
        }
      }
    }
  ])
})

graph.on('edge:mouseleave', ({ edge }) => {
  edge.removeTools()      // 移出时隐藏工具
})

// let hoveredPortId = null; // 记录当前悬停的连接点ID

// // 1. 连接点鼠标进入事件
// graph.on('port:mouseenter', ({ node, port }) => {
//   // 如果已有悬停的连接点，先恢复其样式
//   if (hoveredPortId) {
//     const prevPort = node.getPort(hoveredPortId);
//     if (prevPort) {
//       node.portProp(hoveredPortId, 'attrs/circle', {
//         stroke: '#5F95FF',
//         fill: '#fff',
//         style: { visibility: 'hidden' }
//       });
//     }
//   }

//   // 设置当前连接点为红色并显示
//   node.portProp(port.id, 'attrs/circle', {
//     stroke: '#ff4d4f',
//     fill: '#ffccc7',
//     style: { visibility: 'visible' }
//   });

//   hoveredPortId = port.id; // 更新当前悬停ID
// });

// // 2. 连接点鼠标离开事件
// graph.on('port:mouseleave', ({ node, port }) => {
//   if (hoveredPortId === port.id) {
//     node.portProp(port.id, 'attrs/circle', {
//       stroke: '#5F95FF',
//       fill: '#fff',
//       style: { visibility: 'hidden' }
//     });
//     hoveredPortId = null; // 清除悬停状态
//   }
// });


// graph.on('node:mouseenter', ({ node }) => {
//   const ports = node.getPorts();
//   console.log("...............................")
//   console.log(ports)
//   ports.forEach(port => {
//     node.portProp(port.id, 'attrs/circle', {
//       stroke: '#ff4d4f',
//       fill: '#ffccc7',
//       style: { visibility: 'visible' }
//     });
//   });
// });

// graph.on('node:mouseleave', ({ node }) => {
//   const ports = node.getPorts();
//   ports.forEach(port => {
//     node.portProp(port.id, 'attrs/circle', {
//       stroke: '#5F95FF',
//       fill: '#fff',
//       style: { visibility: 'hidden' }
//     });
//   });
// });


  listen("returned_command", (ev: { payload: unknown }) => {
    if (lednode === null) return;
    let payload = ev.payload as string;
    let val = parseInt(payload, 16);
    if (val === 0x20) {
      lednode.setAttrs({ body: { fill: "#fff" }, label: { fill: "#000" } });
    } else if (val === 0) {
      lednode.setAttrs({ body: { fill: "#555" }, label: { fill: "#fff" } });
    }
  });

  async function onclick(
    sourceLabel,
    select1Value,
    input1,
    select2Value,
    input2
  ) {
    console.log("sourceLabel:", sourceLabel);
    console.log("sourceLabeltype:", typeof sourceLabel);
    console.log("select1Value:", select1Value);
    console.log("select1Valuetype:", typeof select1Value);
    console.log("input1:", input1);
    console.log("input1type:", typeof input1);
    console.log("select2Value:", select2Value);
    console.log("input2:", input2);
    // 在用invoke向tauri传递参数的时候要注tyvue这边的参数名称可能与tauri那边不一致。
    invoke("add_repl", {
      source: sourceLabel, //小灯LED
      target: select1Value, //gpioPortC
      targetValue: input1,  //13
      interruptTarget: select2Value, //none
      interruptIndex: input2,
    });
  }

  function showContextMenu(sourceLabel: string) {
    const contextMenu = document.createElement("div");
    contextMenu.style.left = `${(event as MouseEvent).clientX}px`;
    contextMenu.style.top = `${(event as MouseEvent).clientY}px`;
  }

  // #endregion

  // #region 初始化图形
const commonPortAttrs = {
  circle: {
    r: 4,
    magnet: true,
    stroke: "#5F95FF",
    strokeWidth: 1,
    fill: "#fff",
    style: {
      visibility: "hidden",
    },
  },
};

let globalIndex = 0;
const stm32f103list1=['VDD','VSS','PB9','PB8','B00T0','PB7','PB6','PB5','PB4','PB3','PA15','PA14'];
const stm32f103list2=['VDD','VSS','PA13','PA12','PA11','PA10','PA9','PA8','PB15','PB14','PB13','PB12'];
const stm32f103list3=['PA3','pa4','PA5','PA6','PA7','PB0','PB1','PB2','PB10','PB11','VSS','VDD'];
const stm32f103list4=['VBAT','PC13','PC14','PC15','PD0','PD1','NRST','VSSA','VDDA','PA0','PA1','PA2'];
function createPorts(positionName: string,start: number, count: number,initialOffset:number,list:Array<string>) {
  const items: {group: string; id: string; port: string}[] = [];
  const groups = Array.from({ length: count }, (_, i) => {
    const portName = `point${++globalIndex}`;
    const baseOffset = start + i * 15.5;
     items.push({
      group: portName,
      id: portName,  
      port:list[i],  
     });
    if (positionName === "top"||positionName === "bottom") {
      return {
        [portName]: {
          position: {name: positionName,args: {dx: baseOffset,dy: initialOffset}},
          attrs: commonPortAttrs
        }
      };
    } else {
      return {
        [portName]: {
          position: { name: positionName, args: { dx: initialOffset, dy: baseOffset } },
          attrs: commonPortAttrs
        }
      };
    }
  }).reduce((acc, curr) => ({ ...acc, ...curr }), {});
  // const items = Object.keys(groups).map(group => ({ group }));
  
  return { groups, items };
}

function mergePorts(...allPorts: ReturnType<typeof createPorts>[]) {
  return {
    groups: Object.assign({}, ...allPorts.map(p => p.groups)),
    items: ([] as {group: string}[]).concat(...allPorts.map(p => p.items))
  };
}

const ports=mergePorts(createPorts("top",0,1,0,['hhh']),createPorts("bottom",0,1,0,['hhh']),createPorts("left",0,1,0,['hhh']),createPorts("right",0,1,0,['hhh']));

  Graph.registerNode(
    "custom-rect",
    {
      inherit: "rect",
      width: 66,
      height: 36,
      attrs: {
        body: {
          strokeWidth: 1,
          stroke: "#5F95FF",
          fill: "#EFF4FF",
        },
        text: {
          fontSize: 12,
          fill: "#262626",
        },
      },
      ports: ports,
    },
    true
  );

  Graph.registerNode(
    "custom-save",
    {
      inherit: "rect",
      width: 100,
      height: 100,
      markup: [
        {
          tagName: "rect",
          selector: "body",
        },
        {
          tagName: "image",
        },
        {
          tagName: "text",
          selector: "label",
        }
      ],
      attrs: {
        body: {
          stroke: "#E0FFFF",
          fill: "#ffffff",
        },
        image: {
          width: 100,
          height: 180,
          refX: 0,
          refY: -70,
        },
        label: {
          refY: 70,
          textAnchor: "middle",
          textVerticalAnchor: "top",
          fontSize: 17,
          fill: "#000000",
        },
      },
    },
    true
  );

  Graph.registerNode(
    "custom-polygon",
    {
      inherit: "polygon",
      width: 66,
      height: 36,
      attrs: {
        body: {
          strokeWidth: 1,
          stroke: "#5F95FF",
          fill: "#EFF4FF",
        },
        text: {
          fontSize: 12,
          fill: "#262626",
        },
      },
      ports: {
        ...ports,
        items: [
          {
            group: "top",
          },
          {
            group: "bottom",
          },
        ],
      },
    },
    true
  );

  Graph.registerNode(
    "custom-circle",
    {
      inherit: "circle",
      width: 45,
      height: 45,
      attrs: {
        body: {
          strokeWidth: 1,
          stroke: "#5F95FF",
          fill: "#EFF4FF",
        },
        text: {
          fontSize: 12,
          fill: "#262626",
        },
      },
      ports: ports,
    },
    true
  );

  Graph.registerNode(
    "custom-image",
    {
      inherit: "rect",
      width: 100,
      height: 100,
      markup: [
        {
          tagName: "rect",
          selector: "body",
        },
        {
          tagName: "image",
        },
        {
          tagName: "text",
          selector: "label",
        }
      ],
      attrs: {
        body: {
          stroke: "#DCDCDC",
          fill: "#DCDCDC",
        },
        image: {
          width: 100,
          height: 100,
          preserveAspectRatio: 'xMidYMid meet',
        },
        label: {
          refY: 110,
          textAnchor: "middle",
          textVerticalAnchor: "top",
          fontSize: 14,
          fill: "#000000",
        },
      },
    },
    true
  );
  const r1 = graph.createNode({
    shape: "custom-image",
    label: "LED",
    attrs: {
      image: {
        "xlink:href": "../../public/peripherals/f3e38030cc2615977cc05f711b662e79.png",
      },
    },
    ports:mergePorts(createPorts("bottom",-20,1,0,['1']),createPorts("bottom",20,1,0,['1'])),
    data: {
      image: {
        width: 140,
        height: 140,
      },
      label: {
        refX: 70,
        refY: 0,
        fontSize:14,
      },
    },
  });
  console.log(r1.getPorts());
  
  const r2 = graph.createNode({
    shape: "custom-image",
    label: "按钮",
    attrs: {
      image: {
        "xlink:href": "../../public/peripherals/85a8f37d7cac59832496fffe7d1eb5db.png",
      },
    },
    ports:mergePorts(createPorts("bottom",-19,1,-3,['hhh']),createPorts("bottom",19,1,-3,['hhh']),createPorts("top",-19,1,3,['hhh']),createPorts("top",19,1,3,['hhh'])),
    data: {
      image: {
        width: 100,
        height: 140,
      },
      label: {
        refX: -20,
        refY: 65,
        fontSize:14,
      },
    },
  });
  const r3 = graph.createNode({
    shape: "custom-image",
    label: "温度传感器",
    attrs: {
      image: {
        "xlink:href": "../../public/peripherals/cd018e3f8fe89027702f0f696351a730.png",
      },
    },
    ports:mergePorts(createPorts("bottom",-17,3,-7,['1'])),
    data: {
      image: {
        width: 100,
        height: 220,
      },
      label: {
        refX: 50,
        refY: -15,
        fontSize:14,
      },
    },
  });
  const r4 = graph.createNode({
    shape: "custom-image",
    label: "OLED显示屏",
    attrs: {
      image: {
        "xlink:href": "../../public/peripherals/8ef7ba7232822329e714a8a55eb580a9.png",
      },
    },
    ports:mergePorts(createPorts("top",-23,4,5,['1'])),
    data: {
      image: {
        width: 280,
        height: 260,
      },
      label: {
        refX: -50,
        refY: 127,
        fontSize:14,
      },
    },
  });
  const r5 = graph.createNode({
    shape: "custom-image",
    label: "蜂鸣器",
    attrs: {
      image: {
        "xlink:href": "../../public/peripherals/0e0a7ec038287a93af468215a7f52976.png",
      },
    },
    ports:mergePorts(createPorts("bottom",-16,3,0,['1'])),
    data: {
      image: {
        width: 140,
        height: 180,
      },
      label: {
        refX: 50,
        refY: -15,
        fontSize:14,
      },
    },
  });
  const r6 = graph.createNode({
    shape: "custom-image",
    label: "共阳1位数码管",
    attrs: {
      image: {
        "xlink:href": "../../public/peripherals/c336a55b1197ba48ff0fc02570b950d5.png",
      },
    },
    ports:mergePorts(createPorts("bottom",-62,9,0,['1'])),
    data: {
      image: {
        width: 180,
        height: 280,
      },
      label: {
        refX: 90,
        refY: -25,
        fontSize:14,
      },
    },
  });
  stencil.load([r1, r2, r3, r4, r5, r6], "group1");

  const imageShapes = [
    {
      label: "STM32F4\nDiscovery",
      image: "../../public/Arduino_DUE_V02b_breadboard.svg",
      width1: 620,
      height1: 320,
      refX1: 300,
      refY1: -30,
      fontSize:14,
      //'https://gw.alipayobjects.com/zos/bmw-prod/687b6cb9-4b97-42a6-96d0-34b3099133ac.svg',
      ports: mergePorts(createPorts("top",-187,10,15,['1']),createPorts("top",-25.5,8,15,['1']),createPorts("top",111.5,8,15,['1']),createPorts("right",-146.5,18,-47,['1']),createPorts("right",-146.5,18,-28,['1']),createPorts("bottom",-132.5,8,-18,['1']),createPorts("bottom",4.5,8,-18,['1']),createPorts("bottom",141.5,8,-18,['1'])),
    },
    {
      label: "E906",
      image: '../../public/b86c40b773860d353f5498f709a4c83d.png',
      width1: 335,
      height1: 320,
      refX1: 0,
      refY1: 0,
      fontSize:0,
      ports:mergePorts(createPorts("top",-112,16,3,['1']),createPorts("bottom",-112,16,-3,['1']),createPorts("left",-112,16,10,['1']),createPorts("right",-112,16,-10,['1'])),
    },
    {
      label: "Arudino uno",
      image: "../../public/image.png",
      width1: 440,
      height1: 320,
      refX1: 240,
      refY1: -30,
      fontSize:14,
      ports: mergePorts(createPorts("top",-80.5,10,15,['1']),createPorts("top",81,8,15,['1']),createPorts("bottom",-26,8,-15,['1']),createPorts("bottom",111,6,-15,['1'])),
    },
    {
      label: "STM32F103C8",
      image: "../../public/6a64bc114ad280cd76bd14dcfb48d7ab.png",
      width1: 275,
      height1: 275,
      refX1: 0,
      refY1: 0,
      fontSize:0,
     ports: mergePorts(createPorts("top",-86,12,3,stm32f103list1),createPorts("bottom",-86,12,-3,stm32f103list3),createPorts("left",-86,12,3,stm32f103list4),createPorts("right",-86,12,-3,stm32f103list2)),
    },
    {
      label: "NXP",
      image: "https://gw.alipayobjects.com/zos/bmw-prod/c36fe7cb-dc24-4854-aeb5-88d8dc36d52e.svg",
    },
    {
      label: "Xtensa",
      image: "https://gw.alipayobjects.com/zos/bmw-prod/2010ac9f-40e7-49d4-8c4a-4fcf2f83033b.svg",
    },
  ];

  graph.on("node:resizing", ({ node }) => {
    const size = node.size();
    node.attr("image/width", size.width);
    node.attr("image/height", size.height);
  });

  const imageNodes = imageShapes.map((item) =>
    graph.createNode({
      shape: "custom-image",
      label: item.label,
      attrs: {
        image: {
          "xlink:href": item.image,
        },
      },
      data: {
        image: {
          width: item.width1,
          height: item.height1,
        },
        label: {
          refX: item.refX1,
          refY: item.refY1,
          fontSize:item.fontSize,
        },
      },
      ports:item.ports,
    })
  );
  stencil.load(imageNodes, "group2");

  const Batterylist = [
    {
      label: "电源负极",
      image:'../../public/battery/c7410ef705eeaaa1e25510c4bc0254dc.png',
    },
    {
      label: "模拟信号电源",
      image: "../../public/battery/39ea5cdc4541e4b232941a1b6753c42d.png",
    },
    {
      label: "接线端子",
      image: "../../public/battery/a273ec10086d189cdfebb584dcaef482.png",
    },
  ];

  const BatteryNodes = Batterylist.map((item) =>
    graph.createNode({
      shape: "custom-image",
      label: item.label,
      attrs: {
        image: {
          "xlink:href": item.image,
        },
      },
     ports:createPorts("top",0,1,0,['1']),
      data: {
        image: {
          width: 60,
          height: 60,
        },
        label: {
          refX: 4,
          refY: 70,
          fontSize:14,
        },
      },
    })
  );
  stencil.load(BatteryNodes, "group3");
  // #endregion


  // 初始化时加载已保存的图表列表
  for (let i = 0; i < localStorage.length; i++) {
    console.log(localStorage.length);
    const key = localStorage.key(i);
    if (key?.startsWith('x6-graph-')) {
      const name = key.replace('x6-graph-', '');
      if (!savedGraphsName.value.includes(name)) {
        savedGraphsName.value.push(name);
      }
    }
  }
  updateStencilGroup4();
  // #endregion
>>>>>>> v3.0

});

const props = defineProps({
<<<<<<< HEAD
  showTerminal: Boolean
});

// async function saveToFile() {
//   const graphData = graph.toJSON();
//   const jsonStr = JSON.stringify(graphData, null, 2);

//   // 提示用户选择保存的文件路径和文件名
//   const filePath = await save({
//     defaultPath: 'graphData.json',
//     filters: [
//       { name: 'JSON files', extensions: ['json'] },
//       { name: 'All files', extensions: ['*'] },
//     ],
//   });

//   if (filePath) {
//     console.log(filePath);
//     // 使用 Tauri 的 fs 模块保存文件
//     try {
//       await writeTextFile(filePath, jsonStr);
//       console.log('File saved successfully.');
//     } catch (error) {
//       console.log('Error saving file:');
//     }
//   }
// }

// async function loadFromFile() {
//   // 提示用户选择打开的文件路径和文件名
//   const filePaths = await open({
//     defaultPath: 'graphData.json',
//     filters: [
//       { name: 'JSON files', extensions: ['json'] },
//       { name: 'All files', extensions: ['*'] },
//     ],
//   });
  
//   if (filePaths && filePaths.length > 0) {
//     // 使用 Tauri 的 fs 模块读取文件内容
//     try {
//       const jsonStr = await readTextFile(filePaths);

//       // 解析 JSON 数据并加载到图表中
//       const graphData = JSON.parse(jsonStr);
//       graph.fromJSON(graphData);

//       console.log('File loaded successfully.');
//     } catch (error) {
//       console.error('Error loading file:', error);
//     }
//   }
// }

</script>




<style>
#antv {
  width: 100%;
  height: 600px;
=======
  showTerminal: Boolean,
});

const linklist=["https://app.puliedu.com/static/png/lab-2-6cd97e85.png","https://app.puliedu.com/static/png/lab-14-2323e614.png","https://app.puliedu.com/static/png/lab-12-59d76508.png","https://app.puliedu.com/static/png/lab-8-a506b82c.png"];
const updateStencilGroup4 = () => {
  const savedNodes = savedGraphsName.value.map(name => {
    console.log("bbbb        "+name);
    return graph.createNode({
      shape: "custom-save",
      label: name,
      attrs: {
        body: {
          fill: "#E6F7FF",
        },
        image:{
          "xlink:href":linklist[Math.floor(Math.random() * linklist.length)],
          //"xlink:href":"../../public/image/"+name+".png",
        },
      },
      data: {
        isSavedGraph: true,
        graphName: name
      },
    });
  });
  console.log(savedNodes.length);
  stencilRef.value.load(savedNodes, "group4");
}

const saveToFile = async () => {
  // const graphData = graph.toJSON(); 
  // localStorage.setItem('x6-graph', JSON.stringify(graphData));
  // alert("保存成功");
  if (currentGraphName.value) {
    // 保存到当前画布
    const graphData = graph.toJSON();
    localStorage.setItem(`x6-graph-${currentGraphName.value}`, JSON.stringify(graphData));
    graph.exportPNG(currentGraphName.value,{
      quality:1,
      backgroundColor:"black"
    });
    alert("保存成功");
  } else {
    // 显示保存对话框
    showSaveDialog.value = true;
  }
}

// 添加新画布保存函数
const saveNewCanvas = async () => {
  if (!newGraphName.value) {
    alert("请输入名称");
    return;
  }
  const graphData = graph.toJSON();
  localStorage.setItem(`x6-graph-${newGraphName.value}`, JSON.stringify(graphData));
  
      graph.exportPNG(newGraphName.value,{
      quality:1,
      backgroundColor:"black"
    });
  // 更新画布列表
  if (!savedGraphsName.value.includes(newGraphName.value)) {
    savedGraphsName.value.push(newGraphName.value);
  }
  currentGraphName.value = newGraphName.value;
  newGraphName.value = '';
  showSaveDialog.value = false;
  
  alert("保存成功");
  updateStencilGroup4();
};

const handleSaveCommand = (command: string) => {
  if (command === 'save_current') {
    saveToFile();
  } else if (command === 'save_new') {
    showSaveDialog.value = true;
  } else if (command.startsWith('load_')) {
    const graphName = command.substring(5);
    const savedData = localStorage.getItem(`x6-graph-${graphName}`);
    if (savedData) {
      graph.fromJSON(JSON.parse(savedData));
      currentGraphName.value = graphName;
      alert("加载成功");
    }
  }
};

const loadFromFile = async () =>  {
  // 提示用户选择打开的文件路径和文件名
  // const filePaths = await open({
  //   defaultPath: "graphData.json",
  //   filters: [
  //     { name: "JSON files", extensions: ["json"] },
  //     { name: "All files", extensions: ["*"] },
  //   ],
  // });

  // if (filePaths && filePaths.length > 0) {
  //   // 使用 Tauri 的 fs 模块读取文件内容
  //   try {
  //     const jsonStr = await readTextFile(filePaths);

  //     // 解析 JSON 数据并加载到图表中
  //     const graphData = JSON.parse(jsonStr);
  //     graph.fromJSON(graphData);
  //     console.log("File loaded successfully.");
  //   } catch (error) {
  //     console.error("Error loading file:", error);
  //   }
  // }

    const savedData = localStorage.getItem('x6-graph-333');
    if (savedData) {
      graph.fromJSON(JSON.parse(savedData)); // 恢复画布
      alert("加载成功");
    }
  }

  const exportto = async () => {
    const canvas = graph.view.canvas;

  // 2. 创建临时Canvas
  const exportCanvas = document.createElement('canvas');
  exportCanvas.width = 1000;
  exportCanvas.height = 500;
 exportCanvas.getContext('2d').drawImage(canvas, 0, 0);

  // 5. 导出为Data URL
  const dataUrl = exportCanvas.toDataURL('image/png');

  // 6. 触发下载
  const link = document.createElement('a');
  link.href = dataUrl;
  link.download = `graph-${Date.now()}.png`;
  link.click();
}
</script>

<style scoped>
#antv {
  width: 100%;
  height: 1000px;
>>>>>>> v3.0
  display: flex;
  border: 1px solid #dfe3e8;
}

#stencil {
  width: 250px;
<<<<<<< HEAD
  height: 600px;
=======
  height: 1000px;
>>>>>>> v3.0
  position: relative;
  border-right: 1px solid #dfe3e8;
}

#graph-container {
  width: 8000px;
<<<<<<< HEAD
  height: 600px;
}

=======
  height: 1000px;
}
.x6-edge {
  z-index: 2; /* 连线层级高于节点（默认节点z-index为1） */
}
>>>>>>> v3.0
.x6-widget-stencil {
  background-color: #fff;
}

.x6-widget-stencil-title {
  background-color: #fff;
}
<<<<<<< HEAD
=======
.x6-widget-stencil-content {
  width: 200px;
}

>>>>>>> v3.0

.x6-widget-stencil-group-title {
  background-color: #fff !important;
}

.x6-widget-transform {
  margin: -1px 0 0 -1px;
  padding: 0px;
  border: 1px solid #239edd;
}

<<<<<<< HEAD
.x6-widget-transform>div {
  border: 1px solid #239edd;
}

.x6-widget-transform>div:hover {
=======
/* 仅悬停的连接点变红 */
.port-hover-target:hover {
  visibility: visible !important;
  stroke: #ff4d4f !important;
  fill: #ffccc7 !important;
  transition: all 0.3s;
}

/* 非悬停的连接点保持隐藏 */
.x6-port-body:not(:hover) {
  visibility: hidden !important;
}

.x6-widget-transform > div {
  border: 1px solid #239edd;
}

.x6-widget-transform > div:hover {
>>>>>>> v3.0
  background-color: #3dafe4;
}

.x6-widget-transform-active-handle {
  background-color: #3dafe4;
}

.x6-widget-transform-resize {
  border-radius: 0;
}

.x6-widget-selection-inner {
  border: 1px solid #239edd;
}

.x6-widget-selection-box {
  opacity: 0;
}
<<<<<<< HEAD
.splitpanes__pane {
  display: flex;
  /* justify-content: center; */
=======
.port-hover-target:hover {
    visibility: visible !important;
    stroke: #ff4d4f !important;
    fill: #ff4d4f !important;
  }
  /* .x6-port-body:not(:hover) {
    visibility: visible !important;
  } */
.splitpanes__pane {
  display: flex;
  justify-content: space-around;
>>>>>>> v3.0
  /* align-items: center; */
  font-family: Helvetica, Arial, sans-serif;
  color: rgba(255, 255, 255, 0.6);
  font-size: 5em;
}
<<<<<<< HEAD
</style>
=======
.header-bar {
  height: 20px; /* 更小的高度 */
  background: linear-gradient(135deg, #1a1a1a 0%, #000000 100%);
  display: flex;
  align-items: center;
  justify-content: center;
  border-bottom: solid #e4e7ed;
  font-size: 25px;
  font-weight: bold;
  color: #303133;
  /* margin-bottom: 20px; */
  padding: 20px 25px;
}

.title-text {
  white-space: nowrap;
  color: #dce0e7;
}
</style>
>>>>>>> v3.0
